﻿using System;
using System.Windows;
using ChiWalker.Dynamics;
using ChiWalker.Helpers;
using ChiWalker.Routines;
using ChiWalker.Settings;
using ChiWalker.Utilities;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.TreeSharp;

namespace ChiWalker
{
    internal class ChiWalker : CombatRoutine
    {
        private static WoWSpec _mySpec = WoWSpec.None;
        private static WoWClass _myClass = WoWClass.None;
        private static string _name;
        private Composite _combat;
        private Composite _combatBuffsBehavior;
        private Window _configWindow;
        private Composite _healBehavior;
        private Composite _preCombatBuffsBehavior;
        private Composite _pullBehavior;
        private Composite _restBehavior;

        public ChiWalker()
        {
            Instance = this;
            BotEvents.OnBotStartRequested += OnStartCheckSpec;
        }

        public static ChiWalker Instance { get; private set; }

        public override WoWClass Class
        {
            get
            {
                if (_myClass == WoWClass.None)
                    _myClass = StyxWoW.Me.Class;
                return _myClass;
            }
        }

        public override string Name
        {
            get { return _name ?? (_name = string.Format("ChiWalker: {0}", Class)); }
        }

        public override bool WantButton
        {
            get { return true; }
        }

        public override Composite CombatBehavior
        {
            get { return _combat; }
        }

        public override Composite CombatBuffBehavior
        {
            get { return _combatBuffsBehavior; }
        }

        public override Composite HealBehavior
        {
            get { return _healBehavior; }
        }

        public override Composite PreCombatBuffBehavior
        {
            get { return _preCombatBuffsBehavior; }
        }

        public override Composite PullBehavior
        {
            get { return _pullBehavior; }
        }

        public override Composite RestBehavior
        {
            get { return _restBehavior; }
        }


        private void OnStartCheckSpec(EventArgs args)
        {
            if (RoutineManager.Current.Name == Instance.Name)
            {
                Logger.WriteVerbose("Checking spec: Currently using routine for {0}, I'm {1}", _mySpec,
                    StyxWoW.Me.Specialization);
                if (_mySpec != StyxWoW.Me.Specialization)
                {
                    Logger.WriteError("Detected Specialization Change");
                    Logger.WriteError("The bot is currently running the routine for {0}", _mySpec);
                    Logger.WriteError("This WILL cause you problems");
                    Logger.WriteError("Restart the bot or change back spec to continue");
                }
                Glyph.UpdateGlyphList();
            }
        }

        public override void OnButtonPress()
        {
            _configWindow = new ConfigWindow("Pet Battle Settings", Name, "Nuok", 350, 400);
            _configWindow.Show();
            _configWindow.Closed += ConfigWindowOnClosed;
        }

        private void ConfigWindowOnClosed(object sender, EventArgs e)
        {
            ChiWalkerSettings.SaveAll();
        }

        public override void Initialize()
        {
            Logger.Write("{0} Loading", Name);
            Glyph.UpdateGlyphList();
            UpdateSpec();
            CreateBehavoirs();
            EventHandlers.Init();
            Logger.Write("Finshed Loading");
        }

        private static void UpdateSpec()
        {
            if (StyxWoW.IsInGame && _mySpec != StyxWoW.Me.Specialization)
            {
                _mySpec = StyxWoW.Me.Specialization;
                Logger.Write("Loading Routine for {0}", Logger.SplitCamelCase(_mySpec.ToString()));
            }
        }

        public bool CreateBehavoirs()
        {
            int count;

            _combat = SpecBuilder.GetSpecRoutine(Class, _mySpec, BehaviorType.Combat, out count);
            if (count == 0 || _combat == null)
            {
                Logger.Write("Sorry I havent coded for this spec yet :(");
                return false;
            }

            _combatBuffsBehavior =
                new LockSelector(SpecBuilder.GetSpecRoutine(Class, _mySpec, BehaviorType.CombatBuffs, out count));
            _healBehavior = new LockSelector(SpecBuilder.GetSpecRoutine(Class, _mySpec, BehaviorType.Heal, out count));
            _preCombatBuffsBehavior =
                new LockSelector(SpecBuilder.GetSpecRoutine(Class, _mySpec, BehaviorType.PreCombatBuffs, out count));
            _pullBehavior = new LockSelector(SpecBuilder.GetSpecRoutine(Class, _mySpec, BehaviorType.Pull, out count));
            _restBehavior = new LockSelector(RestRoutine.ChiRest());

            return true;
        }

        #region Nested type: LockSelector

        /// <summary>
        ///     This behavior wraps the child behaviors in a 'FrameLock' which can provide a big performance improvement
        ///     if the child behaviors makes multiple api calls that internally run off a frame in WoW in one CC pulse.
        /// </summary>
        public class LockSelector : PrioritySelector
        {
            public LockSelector(params Composite[] children)
                : base(children)
            {
            }

            public override RunStatus Tick(object context)
            {
                using (StyxWoW.Memory.AcquireFrame())
                {
                    return base.Tick(context);
                }
            }
        }

        #endregion
    }
}